package com.example.springboot.system.controller;

import com.alibaba.excel.EasyExcel;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springboot.common.annotate.JwtToken;
import com.example.springboot.common.resp.Result;
import com.example.springboot.common.utils.JWTUtils;
import com.example.springboot.common.utils.UUIDUtils;
import com.example.springboot.system.entity.*;
import com.example.springboot.system.mapper.BorrowMapper;
import com.example.springboot.system.service.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 图书借还流水表 前端控制器
 * </p>
 *
 * @author he
 * @since 2024-05-28
 */

@Tag(name = "借阅管理")
@RestController
@RequestMapping("/borrowEntity")
public class BorrowController {

//    @Data
//    static class Borrow {
//        private Integer id;
//        private String serial;
//        private Integer booknoId;
//        private String booknoCode;
//        private String booknoName;
//        private Integer userId;
//        private String userAcc;
//        private String userName;
//        private Integer type;
//        private String createBy;
//        private String createTime;
//        private String updateBy;
//        private String updateTime;
//        private Integer undock;
//        private Integer unlucky;
//        private String remark;
//    }

    @Autowired
    private BorrowMapper borrowMapper;

    @Autowired
    private BorrowService borrowService;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @JwtToken
    @Operation(summary = "列表分页")
    @PostMapping("/listPageBorrow")
    public Result<?> listPageBorrow(@RequestParam Integer page, @RequestParam Integer pageSize) {
        //分页参数
        Page<BorrowEntity> rowPage = new Page(page, pageSize);
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("undock", 1);
        rowPage = borrowMapper.selectPage(rowPage, wrapper);
//        List<BorrowEntity> records = rowPage.getRecords();
//        ArrayList<Borrow> list = new ArrayList<>();
//        for (int i = 0; i < records.size(); i++) {
//            BorrowEntity entity = records.get(i);
//            Borrow borrow = new Borrow();
//            BeanUtils.copyProperties(entity,borrow);
//            //查找书本code何用户name
//            BooknoEntity bookno = booknoService.getById(borrow.getBooknoId());
//            borrow.setBooknoCode(bookno.getCode());
//            borrow.setBooknoName(bookno.getName());
//            UserEntity user = userService.getById(borrow.getUserId());
//            borrow.setUserName(user.getName());
//            list.add(borrow);
//        }
//        Page<Borrow> rowPageBorrow = new Page(page, pageSize);
//        rowPageBorrow.setRecords(list);
        return Result.success("数据请求成功", rowPage);
    }

    @JwtToken
    @Operation(summary = "查询编号")
    @PostMapping("/findByIDBorrow/{param}")
    public Result<?> findByIDBorrow(@PathVariable @Validated String param) {
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.like(("borrow_id"), param);
        wrapper.eq(("undock"), 1);
        if (borrowService.count(wrapper) == 0) return Result.success("查询成功，但符合条件数据为空");
        return Result.success("查询成功", borrowMapper.selectList(wrapper));
    }

    @JwtToken
    @Operation(summary = "查询名称")
    @PostMapping("/findByNameBorrow/{param}")
    public Result<?> findByNameBorrow(@PathVariable @Validated String param) {
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.like(("borrow_name"), param);
        wrapper.eq(("undock"), 1);
        if (borrowService.count(wrapper) == 0) return Result.failure("查询成功，但符合条件数据为空");
        return Result.success("查询成功", borrowMapper.selectList(wrapper));
    }

    @JwtToken
    @Operation(summary = "条件查询")
    @PostMapping("/findBorrow")
    public Result<?> findBorrow(@RequestBody BorrowEntity entity) {
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        if (entity.getSerial() != "") wrapper.like(("borrow_serial"), entity.getSerial());
        if (entity.getBooknoCode() != "") wrapper.like(("borrow_bookno_code"), entity.getBooknoCode());
        if (entity.getBooknoName() != "") wrapper.like(("borrow_bookno_name"), entity.getBooknoName());
        if (entity.getUserName() != "") wrapper.like(("borrow_user_name"), entity.getUserName());
        if (entity.getType() != 2) wrapper.like(("borrow_type"), entity.getType());
        wrapper.like(("unlucky"), entity.getUnlucky());
        wrapper.eq(("undock"), 1);
        if (borrowService.count(wrapper) == 0) return Result.failure("查询成功，但符合条件数据为空");
//        List<BorrowEntity> entityList = borrowMapper.selectList(wrapper);
//        ArrayList<Borrow> list = new ArrayList<>();
//        for (int i = 0; i < entityList.size(); i++) {
//            BorrowEntity borrowEntity = entityList.get(i);
//            Borrow borrow = new Borrow();
//            BeanUtils.copyProperties(borrowEntity,borrow);
//            //查找书本code何用户name
//            BooknoEntity bookno = booknoService.getById(borrow.getBooknoId());
//            borrow.setBooknoCode(bookno.getCode());
//            borrow.setBooknoName(bookno.getName());
//            UserEntity user = userService.getById(borrow.getUserId());
//            borrow.setUserName(user.getName());
//            list.add(borrow);
//        }
        return Result.success("查询成功", borrowMapper.selectList(wrapper));
    }


    @JwtToken
    @Operation(summary = "保存数据")
    @PostMapping("/insert")
    public Result<?> insertBorrow(@RequestBody @Validated BorrowEntity entity, HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        //保存
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(("borrow_id"), entity.getId());
        if (borrowService.count(wrapper) != 0) return Result.failure("保存失败，编号已存在");
        String name = decodedJWT.getClaim("name").asString();
        //设置创建者
        entity.setCreateBy(name);
        entity.setCreateTime(sdf.format(new Date()));
        if (borrowService.save(entity)) return Result.success("保存成功");
        return Result.failure("系统超时，保存失败");
    }

    @JwtToken
    @Operation(summary = "永久删除")
    @PostMapping("/delete/{param}")
    public Result<?> deleteBorrow(@PathVariable @Validated String param) {
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(("borrow_id"), param);
        if (borrowService.count(wrapper) == 0) return Result.failure("删除失败，编号不存在");
        if (borrowService.remove(wrapper)) return Result.success("删除成功");
        return Result.failure("系统超时，删除失败");
    }

    @JwtToken
    @Operation(summary = "暂时删除")
    @PostMapping("/deleteTemp/{param}")
    public Result<?> deleteTempBorrow(@PathVariable @Validated String param, HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        //修改
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(("borrow_id"), param);
        if (borrowService.count(wrapper) == 0) return Result.failure("删除失败，编号不存在");
        BorrowEntity borrow = borrowService.getOne(wrapper);
        borrow.setUndock(0);
        //设置修改者
        String name = decodedJWT.getClaim("name").asString();
        borrow.setUpdateBy(name);
        borrow.setUpdateTime(sdf.format(new Date()));
        if (borrowService.updateById(borrow)) return Result.success("删除成功");
        return Result.failure("系统超时，删除失败");
    }

    @JwtToken
    @Operation(summary = "恢复列表")
    @PostMapping("/recoverList")
    public Result<?> recoverListBorrow() {
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("undock", 0);
        return Result.success(borrowMapper.selectList(wrapper));
    }

    @JwtToken
    @Operation(summary = "恢复数据")
    @PostMapping("/recover/{param}")
    public Result<?> recoverBorrow(@PathVariable @Validated String param, HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        //修改
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(("borrow_id"), param);
        if (borrowService.count(wrapper) == 0) return Result.failure("恢复失败，编号不存在");
        BorrowEntity borrow = borrowService.getOne(wrapper);
        borrow.setUndock(1);
        //设置修改者
        String name = decodedJWT.getClaim("name").asString();
        borrow.setUpdateBy(name);
        borrow.setUpdateTime(sdf.format(new Date()));
        if (borrowService.updateById(borrow)) return Result.success("数据恢复成功");
        return Result.failure("系统超时，数据恢复失败");
    }

    @JwtToken
    @Operation(summary = "修改编号")
    @PostMapping("/update")
    public Result<?> updateBorrow(@RequestBody @Validated BorrowEntity entity, HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        //修改
        QueryWrapper<BorrowEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(("borrow_id"), entity.getId());
        if (borrowService.count(wrapper) == 0) return Result.failure("修改失败，编号不存在");
        //设置修改者
        String name = decodedJWT.getClaim("name").asString();
        entity.setUpdateBy(name);
        entity.setUpdateTime(sdf.format(new Date()));
        if (borrowService.updateById(entity)) return Result.success("修改成功");
        return Result.failure("系统超时，修改失败");
    }

    @Operation(summary = "导出数据")
    @PostMapping("exportExcel")
    public void exportExcelBorrow(HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("Excel数据表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        List<BorrowEntity> list = borrowService.list();
        response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), BorrowEntity.class).sheet("Excel数据表").doWrite(list);
    }

    @JwtToken
    @Operation(summary = "导入数据")
    @PostMapping("/importExcel")
    public Result<?> importExcelBorrow(MultipartFile file, HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        try {
            //获取文件的输入流
            InputStream inputStream = file.getInputStream();
            List<BorrowEntity> list = EasyExcel.read(inputStream) //调用read方法
                    //注册自定义监听器，字段校验可以在监听器内实现
                    //.registerReadListener(new BorrowListener())
                    .head(BorrowEntity.class) //对应导入的实体类
                    .sheet(0) //导入数据的sheet页编号，0代表第一个sheet页，如果不填，则会导入所有sheet页的数据
                    .headRowNumber(1) //列表头行数，1代表列表头有1行，第二行开始为数据行
                    .doReadSync();//开始读Excel，返回一个List<T>集合，继续后续入库操作
            //模拟导入数据库操作
            String name = decodedJWT.getClaim("name").asString();
            for (BorrowEntity entity : list) {
                entity.setCreateBy(name);
                entity.setCreateTime(sdf.format(new Date()));
                borrowService.saveOrUpdate(entity);
            }
            return Result.success("导入成功");
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }


    @Autowired
    private UserService userService;

    @Autowired
    private BooknoService booknoService;

    @Autowired
    private BooksService booksService;

    @Autowired
    private RoleService roleService;

    @JwtToken
    @Operation(summary = "借阅还书")
    @PostMapping("/borrow")
    public Result<?> borrowBookno(@RequestParam @Validated String bookno_code, @RequestParam Integer type, HttpServletRequest httpServletRequest) throws ParseException {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        String id = decodedJWT.getClaim("id").asString();//获取用户编号
        String acc = decodedJWT.getClaim("acc").asString();
        String name = decodedJWT.getClaim("name").asString();
        //获取书本信息
        QueryWrapper<BooknoEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("bookno_code", bookno_code);
        BooknoEntity bookno = booknoService.getOne(wrapper);
        if (bookno == null) return Result.failure(type == 1 ? "还书失败，书本不存在" : "借书失败，书本不存在");
        if (bookno.getBorrow() == 0 && type == 0) return Result.failure("借书失败，书本已借出");
        if (bookno.getBorrow() == 1 && type == 1) return Result.failure("还书失败，书本在库");
        UserEntity user = userService.getById(id);
        //修改书册books
        BooksEntity books = booksService.getOne(new QueryWrapper<BooksEntity>().eq("books_id", bookno.getBooksId()));
        //获取用户角色
        Integer roleId = user.getRoleId();
        RoleEntity role = roleService.getById(roleId);
        BooknoEntity booknoEntity = new BooknoEntity();
        if (type == 0) {    // >>>>>>>>>>>>>>> 借书
            //检查用户借书数量
            Integer limitBook = role.getLimitBook();
            QueryWrapper<BooknoEntity> wrapperBN = new QueryWrapper<>();
            wrapperBN.eq("bookno_user_id", id);
            long count = booknoService.count(wrapperBN);
            if (count >= limitBook) return Result.failure("借书失败，超过最大借书数量");
            BeanUtils.copyProperties(bookno, booknoEntity);
            booknoEntity.setBorrow(type);
            booknoEntity.setUserId(id);
            booknoEntity.setBorrowDate(sdf.format(new Date()));
            books.setInventory(books.getInventory() - 1);
        }
        if (type == 1) {    // >>>>>>>>>>>>>>> 还书
            //检查是否是同一个人还书
            if (!id.equals(bookno.getUserId())) {
                return Result.failure("还书失败，请使用借书账号还书");
            }
            //检查用户借书天数
            Integer limitDay = role.getLimitDay();
            String borrowDate = bookno.getBorrowDate();
            //计算时间差
            Date parse = sdf.parse(borrowDate);
            Date date = new Date();
            long time = date.getTime() - parse.getTime();
            long day = time / (1000 * 24 * 60 * 60);
            if (day > limitDay) return Result.failure("还书失败，超出最大还书期限，请前往前台人工还书");
            BeanUtils.copyProperties(bookno, booknoEntity);
            booknoEntity.setBorrow(type);
            booknoEntity.setUserId(null);
            booknoEntity.setBorrowDate("");
            books.setInventory(books.getInventory() + 1);
        }
        //添加borrow订单
        BorrowEntity borrow = new BorrowEntity();
        borrow.setSerial(UUIDUtils.getUUID());
        borrow.setBooknoId(bookno.getId());//书本信息
        borrow.setBooknoCode(bookno.getCode());
        borrow.setBooknoName(bookno.getName());
        borrow.setUserId(user.getId());//用户信息
        borrow.setUserAcc(user.getAcc());
        borrow.setUserName(user.getName());
        borrow.setType(type);
        borrow.setCreateBy(user.getName());
        borrow.setCreateTime(sdf.format(new Date()));
        if (!borrowService.save(borrow)) {
            return Result.failure(type == 1 ? "还书失败，生成流水号错误" : "借书失败，生成流水号错误");
        }
        if (booknoService.updateById(booknoEntity) && booksService.updateById(books)) {
            return Result.success(type == 1 ? "还书成功" : "借书成功");
        }
        return Result.failure("系统超时，失败");
    }

    @JwtToken
    @Operation(summary = "我的借阅")
    @PostMapping("/findBorrowUser")
    public Result<?> findBorrowUser(HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        DecodedJWT decodedJWT = JWTUtils.resolveToken(token);
        String name = decodedJWT.getClaim("name").asString();
        //获取书本信息
        List<BorrowEntity> list = borrowMapper.selectList(new QueryWrapper<BorrowEntity>().eq("borrow_user_name", name));
        return Result.success("数据请求成功", list);
    }

    @Data
    static class Books {
        private String name;
        private Integer value;
    }

    @JwtToken
    @Operation(summary = "借阅图表")
    @PostMapping("/findBorrowEcharts")
    public Result<?> findBorrowEcharts(@RequestParam Boolean isCollepse) throws ParseException {
        int month = 7;
        if (isCollepse) month = 30;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String start = sdf.format(new Date());
        Date parse = sdf.parse(start);
        long time = parse.getTime();
        ArrayList<String> dates = new ArrayList<>();
        ArrayList<Integer> borrow = new ArrayList<>();
        ArrayList<Integer> back = new ArrayList<>();
        ArrayList<Books> books = new ArrayList<>();
        ArrayList<BorrowEntity> arrayList = new ArrayList<>();
        //获取每一天的借阅次数
        for (int i = 0; i < month; i++) {
            long end = time - (1000L * 24 * 60 * 60 * i);
            String format = DateFormatUtils.format(end, "yyyy-MM-dd");
            dates.add(format);
            //获取每一天的借次数
            QueryWrapper<BorrowEntity> wrapperB = new QueryWrapper<>();
            wrapperB.like("create_time", format).eq("borrow_type", 0);
            long count = borrowService.count(wrapperB);
            borrow.add((int) count);
            //获取每一天的还次数
            QueryWrapper<BorrowEntity> wrapperK = new QueryWrapper<>();
            wrapperK.like("create_time", format).eq("borrow_type", 1);
            long lount = borrowService.count(wrapperK);
            back.add((int) lount);
            //获取每本书的借阅次数
            QueryWrapper<BorrowEntity> wrapperBS = new QueryWrapper<>();
            wrapperBS.like("create_time", format).eq("borrow_type", 0);
            List<BorrowEntity> list = borrowService.list(wrapperBS);
            arrayList.addAll(list);
        }
        //关键算法
        Map<String, Integer> CountMap = new HashMap<>();
        for (BorrowEntity book : arrayList) {
            Integer booknoId = book.getBooknoId();
            BooknoEntity bookno = booknoService.getById(booknoId);
            if (bookno != null) {
                CountMap.put(bookno.getName(), CountMap.getOrDefault(bookno.getName(), 0) + 1);
            }
        }
        for (Map.Entry<String, Integer> entry : CountMap.entrySet()) {
            //System.out.println("书名：" + entry.getKey() + " 出现次数：" + entry.getValue());
            //创建新的类
            Books bookBS = new Books();
            bookBS.setName(entry.getKey());
            bookBS.setValue(entry.getValue());
            books.add(bookBS);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("date", dates);
        map.put("borrow", borrow);
        map.put("back", back);
        map.put("books", books);
        return Result.success("数据请求成功", map);
    }

}
